#region License
// Copyright 2007-2008 Rory Plaire (codekaizen@gmail.com)
// Copyright 2010-     Felix Obermaier, 
//                     code adapted from DoubleDouble.java by Martin Davis
//                     http://tsusiatsoftware.net/dd/main.html
/*
 * This license governs use of the accompanying software. If you use the software, you
 * accept this license. If you do not accept the license, do not use the software.
 * 
 * 1. Definitions
 * The terms "reproduce," "reproduction," "derivative works," and "distribution" have the
 * same meaning here as under U.S. copyright law.
 * A "contribution" is the original software, or any additions or changes to the software.
 * A "contributor" is any person that distributes its contribution under this license.
 * "Licensed patents" are a contributor's patent claims that read directly on its contribution.
 * 
 * 2. Grant of Rights
 * (A) Copyright Grant- Subject to the terms of this license, including the license conditions 
 *     and limitations in section 3, each contributor grants you a non-exclusive, worldwide, 
 *     royalty-free copyright license to reproduce its contribution, prepare derivative works 
 *     of its contribution, and distribute its contribution or any derivative works that you create.
 * (B) Patent Grant- Subject to the terms of this license, including the license conditions and 
 *     limitations in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free 
 *     license under its licensed patents to make, have made, use, sell, offer for sale, import, 
 *     and/or otherwise dispose of its contribution in the software or derivative works of the 
 *     contribution in the software.
 * 
 * 3. Conditions and Limitations
 * (A) No Trademark License- This license does not grant you rights to use any contributors' 
 *     name, logo, or trademarks.
 * (B) If you bring a patent claim against any contributor over patents that you claim are 
 *     infringed by the software, your patent license from such contributor to the software 
 *     ends automatically.
 * (C) If you distribute any portion of the software, you must retain all copyright, patent, 
 *     trademark, and attribution notices that are present in the software.
 * (D) If you distribute any portion of the software in source code form, you may do so only under 
 *     this license by including a complete copy of this license with your distribution. If you 
 *     distribute any portion of the software in compiled or object code form, you may only do so 
 *     under a license that complies with this license.
 * (E) The software is licensed "as-is." You bear the risk of using it. The contributors give no 
 *     express warranties, guarantees or conditions. You may have additional consumer rights under 
 *     your local laws which this license cannot change. To the extent permitted under your local laws, 
 *     the contributors exclude the implied warranties of merchantability, fitness for a particular 
 *     purpose and non-infringement.
 * 
 */
#endregion

using System;
using System.Text;
using NPack.Interfaces;

namespace NPack
{
    /// <summary>
    /// A matrix component or matrix element which represents a 
    /// <see cref="System.Double"/>.
    /// </summary>
    /// <remarks>
    /// Use this structure as the type parameter for <see cref="IMatrix{T}"/> when you want
    /// a matrix of Double values, since it implements <see cref="IComputable{T}"/>, which 
    /// allows numerical operations on value types.
    /// </remarks>
    [Serializable]
    public struct DoubleDoubleComponent : IEquatable<DoubleDoubleComponent>,
                                    IComparable<DoubleDoubleComponent>,
                                    IComputable<Double, DoubleDoubleComponent>,
                                    IEquatable<Double>,
                                    IComparable<Double>,
                                    IComputable<Double>,
                                    IConvertible,
                                    IFormattable
    {
        private Double _high, _low;

        /// <summary>
        /// The value nearest to the constant Pi.
        /// </summary>
        public static readonly DoubleDoubleComponent PI = new DoubleDoubleComponent(
            3.141592653589793116e+00,
            1.224646799147353207e-16);

        /// <summary>
        /// The value nearest to the constant 2 * Pi.
        /// </summary>
        public static readonly DoubleDoubleComponent TWO_PI = new DoubleDoubleComponent(
            6.283185307179586232e+00,
            2.449293598294706414e-16);

        /// <summary>
        /// The value nearest to the constant Pi / 2.
        /// </summary>
        public static readonly DoubleDoubleComponent PI_2 = new DoubleDoubleComponent(
            1.570796326794896558e+00,
            6.123233995736766036e-17);

        /// <summary>
        /// The value nearest to the constant e (the natural logarithm base).
        /// </summary>
        public static readonly DoubleDoubleComponent E = new DoubleDoubleComponent(
            2.718281828459045091e+00,
            1.445646891729250158e-16);

        /// <summary>
        /// A value representing the result of an operation which does not return a valid number.
        /// </summary>
        public static readonly DoubleDoubleComponent NaN = new DoubleDoubleComponent(Double.NaN, Double.NaN);

        /// <summary>
        /// A value representing 10
        /// </summary>
        public static readonly DoubleDoubleComponent Ten = new DoubleDoubleComponent(10d);

        /// <summary>
        /// The smallest representable relative difference between two {link @ DoubleDouble} values
        /// </summary>
        public static readonly double EPS = 1.23259516440783e-32;  // = 2^-106

        /// <summary>
        /// The value to split a double-precision value on during multiplication
        /// </summary>
        private const double SPLIT = 134217729.0d; // 2^27+1, for IEEE double

        ///<summary>
        /// Creates a new <see cref="DoubleDoubleComponent"/> converting from the given <paramref name="value"/>.
        ///</summary>
        ///<param name="value">The Double used to set the DoubleDoubleComponent value.</param>
        public DoubleDoubleComponent(Double value)
            :this(value, 0d)
        {
        }

        ///<summary>
        /// Creates a new <see cref="DoubleDoubleComponent"/> converting from the given <paramref name="value"/>.
        ///</summary>
        ///<param name="value">The Double used to set the DoubleDoubleComponent value.</param>
        public DoubleDoubleComponent(DoubleDoubleComponent value)
            :this(value._high, value._low)
        {
        }
        ///<summary>
        /// Creates a new <see cref="DoubleDoubleComponent"/> converting from the given <paramref name="value"/>.
        ///</summary>
        ///<param name="high">The Double used to set the DoubleDoubleComponent value.</param>
        ///<param name="low">The Double used to set the DoubleDoubleComponent value.</param>
        private DoubleDoubleComponent(Double high, Double low)
        {
            _high = high;
            _low = low;
        }
        

        /// <summary>
        /// Returns String representation of this value, in either standard or scientific notation.
        /// If the magnitude of the number is in the range [ 10<sup>-3</sup>, 10<sup>8</sup> ]
        /// standard notation will be used.  Otherwise, scientific notation will be used.
        /// </summary>
        /// <returns>A formatted String displaying this value.</returns>
        public override String ToString()
        {
            int mag = Magnitude(_high);
            if (mag >= -3 && mag <= 20)
                return ToStandardNotation();
            return ToSciNotation();
        }

        /// <summary>
        /// Generates a hash code for the DoubleDoubleComponent value.
        /// </summary>
        /// <returns>A value to represent this value in a hash table.</returns>
        public override Int32 GetHashCode()
        {
            return 7352179 ^ _high.GetHashCode() ^ _low.GetHashCode();
        }

        /// <summary>
        /// Implicitly converts a Double value to a DoubleDoubleComponent.
        /// </summary>
        /// <param name="value">Value to convert.</param>
        /// <returns>
        /// A DoubleDoubleComponent set to <paramref name="value"/>.
        /// </returns>
        public static implicit operator DoubleDoubleComponent(Double value)
        {
            return new DoubleDoubleComponent(value);
        }

        /// <summary>
        /// Explicitly converts a DoubleDoubleComponent to a Double.
        /// </summary>
        /// <param name="component">DoubleDoubleComponent to convert.</param>
        /// <returns>
        /// Value of type Double with the same value as the DoubleDoubleComponent.
        /// </returns>
        public static explicit operator Double(DoubleDoubleComponent component)
        {
            return component._high;
        }

        /// <summary>
        /// Adds a DoubleDoubleComponent and a Double.
        /// </summary>
        /// <param name="lhs">Left hand of the addition operation.</param>
        /// <param name="rhs">Right hand of the addition operation.</param>
        /// <returns>
        /// The sum of <paramref name="lhs"/> and <paramref name="rhs"/>.
        /// </returns>
        public static Double operator +(DoubleDoubleComponent lhs, Double rhs)
        {
            if (lhs.IsNaN()) return Double.NaN;
            return lhs._high + rhs;
        }

        /// <summary>
        /// Subtracts a Double from a DoubleDoubleComponent.
        /// </summary>
        /// <param name="lhs">Left hand of the subtraction operation.</param>
        /// <param name="rhs">Right hand of the subtraction operation.</param>
        /// <returns>
        /// The difference of <paramref name="lhs"/> and <paramref name="rhs"/>.
        /// </returns>
        public static Double operator -(DoubleDoubleComponent lhs, Double rhs)
        {
            if (lhs.IsNaN()) return Double.NaN;
            return lhs._high - rhs;
        }

        #region IEquatable<DoubleDoubleComponent> Members

        /// <summary>
        /// Evaluates equality of two DoubleDoubleComponent instances.
        /// </summary>
        /// <param name="other">The DoubleDoubleComponent to compare to.</param>
        /// <returns>
        /// True if the two DoubleDoubleComponent instances are equal; false otherwise.
        /// </returns>
        public Boolean Equals(DoubleDoubleComponent other)
        {
            return _high == other._high && _low == other._low;
        }

        #endregion

        #region IComparable<DoubleDoubleComponent> Members

        /// <summary>
        /// Compares two DoubleDoubleComponent instances.
        /// </summary>
        /// <param name="other">The DoubleDoubleComponent to compare to.</param>
        /// <returns>
        /// 0 if they are equal,
        /// 1 if the called-on instance is greater, 
        /// -1 if <paramref name="other"/> is greater.
        /// </returns>
        public Int32 CompareTo(DoubleDoubleComponent other)
        {
            if (_high < other._high) return -1;
            if (_high > other._high) return 1;
            if (_low < other._low) return -1;
            if (_low > other._low) return 1;
            return 0;
        }

        #endregion

        #region IAddable<DoubleDoubleComponent> Members

        /// <summary>
        /// Adds two DoubleDoubleComponent values.
        /// </summary>
        /// <param name="a">The other addend.</param>
        /// <returns>
        /// The sum of this DoubleDoubleComponent and <paramref name="a"/>.
        /// </returns>
        public DoubleDoubleComponent Add(DoubleDoubleComponent a)
        {
            double H, h, T, t, S, s, e, f;
            S = _high + a._high;
            T = _low + a._low;
            e = S - _high;
            f = T - _low;
            s = S - e;
            t = T - f;
            s = (a._high - e) + (_high - s);
            t = (a._low - f) + (_low - t);
            e = s + T; H = S + e; h = e + (S - H); e = t + h;

            double zhi = H + e;
            double zlo = e + (H - zhi);

            return  new DoubleDoubleComponent(zhi, zlo);
        }

        #endregion

        #region ISubtractable<DoubleDoubleComponent> Members

        /// <summary>
        /// Subtracts two DoubleDoubleComponent values.
        /// </summary>
        /// <param name="a">The subtrahend.</param>
        /// <returns>
        /// The difference of this DoubleDoubleComponent (minuend) and 
        /// <paramref name="a"/>.
        /// </returns>
        public DoubleDoubleComponent Subtract(DoubleDoubleComponent a)
        {
            if (IsNaN()) return NaN;
            return Add(a.Negative());
        }

        #endregion

        #region IHasZero<DoubleDoubleComponent> Members

        /// <summary>
        /// Returns the zero value for a DoubleDoubleComponent. Equal to 0F.
        /// </summary>
        public DoubleDoubleComponent Zero
        {
            get { return new DoubleDoubleComponent(0); }
        }

        #endregion

        #region INegatable<DoubleDoubleComponent> Members

        /// <summary>
        /// Returns the negation of the DoubleDoubleComponent value. Also the
        /// additive inverse.
        /// </summary>
        /// <remarks>
        /// The value returns solves the following equation:
        /// <code>
        /// DoubleDoubleComponent a = 5, b = a.Negative();
        /// 
        /// Assert.IsTrue(a.Add(b).Equals(0));
        /// </code>
        /// </remarks>
        /// <returns>The negated DoubleDoubleComponent.</returns>
        public DoubleDoubleComponent Negative()
        {
            if (IsNaN()) return NaN;
            return new DoubleDoubleComponent(-_high, -_low);
        }

        #endregion

        #region IMultipliable<DoubleDoubleComponent> Members

        /// <summary>
        /// Multiplies two DoubleDoubleComponents and returns the product.
        /// </summary>
        /// <param name="a">The multiplier.</param>
        /// <returns>
        /// The product of the DoubleDoubleComponent instance and 
        /// <paramref name="a"/>.
        /// </returns>
        public DoubleDoubleComponent Multiply(DoubleDoubleComponent a)
        {
            if (IsNaN() || a.IsNaN()) return NaN;

            Double C = SPLIT * _high; 
            Double hx = C - _high;
            Double c = SPLIT * a._high;
            hx = C - hx; 
            Double tx = _high - hx; 
            Double hy = c - a._high;
            C = _high * a._high; 
            hy = c - hy; 
            Double ty = a._high - hy;
            c = ((((hx * hy - C) + hx * ty) + tx * hy) + tx * ty) + (_high * a._low + _low * a._high);
            Double zhi = C + c; 
            hx = C - zhi;
            Double zlo = c + hx;

            return new DoubleDoubleComponent(zhi, zlo);
        }

        #endregion

        #region IDivisible<DoubleDoubleComponent> Members

        /// <summary>
        /// Divides two DoubleDoubleComponent instances and returns the quotient.
        /// </summary>
        /// <param name="a">The divisor.</param>
        /// <returns>
        /// The quotient of dividing the DoubleDoubleComponent instance
        /// (the dividend) and <paramref name="a"/>.
        /// </returns>
        public DoubleDoubleComponent Divide(DoubleDoubleComponent a)
        {
            Double C = _high / a._high;
            Double c = SPLIT * C; 
            Double hc = c - C; 
            Double u = SPLIT * a._high; 
            hc = c - hc;
            Double tc = C - hc; 
            Double hy = u - a._high; 
            double U = C * a._high; 
            hy = u - hy;
            Double ty = a._high - hy;
            u = (((hc * hy - U) + hc * ty) + tc * hy) + tc * ty;
            c = ((((_high - U) - u) + _low) - C * a._low) / a._high;
            u = C + c;
            double zhi = u;
            double zlo = (C - u) + c;
            return new DoubleDoubleComponent(zhi , zlo);
        }

        #endregion

        #region IHasOne<DoubleDoubleComponent> Members

        /// <summary>
        /// Returns the multiplicative identity.
        /// </summary>
        public DoubleDoubleComponent One
        {
            get { return new DoubleDoubleComponent(1); }
        }

        #endregion

        #region IEquatable<Double> Members

        /// <summary>
        /// Evaluates equality of a DoubleDoubleComponent instance and a Double value.
        /// </summary>
        /// <param name="other">The Double value to compare to.</param>
        /// <returns>
        /// True if the two DoubleDoubleComponent instances are equal; false otherwise.
        /// </returns>
        public Boolean Equals(Double other)
        {
            return _high == other && _low == 0d;
        }

        #endregion

        #region IComparable<Double> Members

        /// <summary>
        /// Compares a DoubleDoubleComponent instance and a Double value.
        /// </summary>
        /// <param name="other">The Double value to compare to.</param>
        /// <returns>
        /// 0 if they are equal,
        /// 1 if the DoubleDoubleComponent instance is greater, 
        /// -1 if <paramref name="other"/> is greater.
        /// </returns>
        public Int32 CompareTo(Double other)
        {
            return CompareTo(new DoubleDoubleComponent(other));
        }

        #endregion

        #region IAddable<Double> Members

        /// <summary>
        /// Adds a DoubleDoubleComponent value and a Double.
        /// </summary>
        /// <param name="a">The other addend.</param>
        /// <returns>
        /// The sum of this DoubleDoubleComponent and <paramref name="a"/>.
        /// </returns>
        Double IAddable<Double>.Add(Double a)
        {
            return Add(new DoubleDoubleComponent(a))._high;
        }

        #endregion

        #region ISubtractable<Double> Members

        /// <summary>
        /// Subtracts a Double value from the DoubleDoubleComponent value.
        /// </summary>
        /// <param name="a">The subtrahend.</param>
        /// <returns>
        /// The difference of this DoubleDoubleComponent (minuend) and 
        /// <paramref name="a"/>.
        /// </returns>
        Double ISubtractable<Double>.Subtract(Double a)
        {
            return Subtract(new DoubleDoubleComponent(a))._high;
        }

        #endregion

        #region IHasZero<Double> Members

        /// <summary>
        /// Gets the additive identity as a Double: 0F.
        /// </summary>
        Double IHasZero<Double>.Zero
        {
            get { return 0.0; }
        }

        #endregion

        #region INegatable<Double> Members

        /// <summary>
        /// Returns the negation of the DoubleDoubleComponent value as a Double. Also the
        /// additive inverse.
        /// </summary>
        /// <remarks>
        /// The value returns solves the following equation:
        /// <code>
        /// DoubleDoubleComponent a = 5, b = a.Negative();
        /// 
        /// Assert.IsTrue(a.Add(b).Equals(0));
        /// </code>
        /// </remarks>
        /// <returns>The negated DoubleDoubleComponent as a Double.</returns>
        Double INegatable<Double>.Negative()
        {
            if (IsNaN()) return Double.NaN;
            return -_high;
        }

        #endregion

        #region IMultipliable<Double> Members

        /// <summary>
        /// Multiplies the DoubleDoubleComponent with Double and returns the product.
        /// </summary>
        /// <param name="a">The multiplier.</param>
        /// <returns>
        /// The product of the DoubleDoubleComponent instance and 
        /// <paramref name="a"/>.
        /// </returns>
        Double IMultipliable<Double>.Multiply(Double a)
        {
            return Multiply(new DoubleDoubleComponent(a))._high;
        }

        #endregion

        #region IDivisible<Double> Members

        /// <summary>
        /// Divides the DoubleDoubleComponent by a Double and returns the quotient.
        /// </summary>
        /// <param name="a">The divisor.</param>
        /// <returns>
        /// The quotient of dividing the DoubleDoubleComponent instance
        /// (the dividend) and <paramref name="a"/>.
        /// </returns>
        Double IDivisible<Double>.Divide(Double a)
        {
            return Divide(new DoubleDoubleComponent(a))._high;
        }

        #endregion

        #region IHasOne<Double> Members

        /// <summary>
        /// Gets the multiplicative identity as a Double: 1F.
        /// </summary>
        Double IHasOne<Double>.One
        {
            get { return 1.0; }
        }

        #endregion

        #region IBooleanComparable<DoubleDoubleComponent> Members

        /// <summary>
        /// Evaluates if the DoubleDoubleComponent instance is greater than 
        /// the given value.
        /// </summary>
        /// <param name="value">The value to compare to.</param>
        /// <returns>True if the DoubleDoubleComponent instance is greater
        /// than <paramref name="value"/>; false otherwise.</returns>
        public Boolean GreaterThan(DoubleDoubleComponent value)
        {
            return _high > value._high || (_high == value._high && _low > value._low);
        }

        /// <summary>
        /// Evaluates if the DoubleDoubleComponent instance is greater than 
        /// or equal to the given value.
        /// </summary>
        /// <param name="value">The value to compare to.</param>
        /// <returns>
        /// True if the DoubleDoubleComponent instance is greater
        /// than or equal to <paramref name="value"/>; false otherwise.
        /// </returns>
        public Boolean GreaterThanOrEqualTo(DoubleDoubleComponent value)
        {
            return (_high > value._high) || (_high == value._high && _low >= value._low);
        }

        /// <summary>
        /// Evaluates if the DoubleDoubleComponent instance is less than 
        /// the given value.
        /// </summary>
        /// <param name="value">The value to compare to.</param>
        /// <returns>True if the DoubleDoubleComponent instance is less
        /// than <paramref name="value"/>; false otherwise.</returns>
        public Boolean LessThan(DoubleDoubleComponent value)
        {
            return (_high < value._high) || (_high == value._high && _low < value._low);
        }

        /// <summary>
        /// Evaluates if the DoubleDoubleComponent instance is less than 
        /// or equal to the given value.
        /// </summary>
        /// <param name="value">The value to compare to.</param>
        /// <returns>
        /// True if the DoubleDoubleComponent instance is less
        /// than or equal to <paramref name="value"/>; false otherwise.
        /// </returns>
        public Boolean LessThanOrEqualTo(DoubleDoubleComponent value)
        {
            return (_high < value._high) || (_high == value._high && _low <= value._low);
        }

        #endregion

        #region IBooleanComparable<Double> Members

        /// <summary>
        /// Evaluates if the DoubleDoubleComponent instance is greater than 
        /// the given Double value.
        /// </summary>
        /// <param name="value">The value to compare to.</param>
        /// <returns>True if the DoubleDoubleComponent instance is greater
        /// than <paramref name="value"/>; false otherwise.</returns>
        public Boolean GreaterThan(Double value)
        {
            return GreaterThan( new DoubleDoubleComponent(value));
        }

        /// <summary>
        /// Evaluates if the DoubleDoubleComponent instance is greater than 
        /// or equal to the given Double value.
        /// </summary>
        /// <param name="value">The value to compare to.</param>
        /// <returns>
        /// True if the DoubleDoubleComponent instance is greater
        /// than or equal to <paramref name="value"/>; false otherwise.
        /// </returns>
        public Boolean GreaterThanOrEqualTo(Double value)
        {
            return GreaterThanOrEqualTo(new DoubleDoubleComponent(value));
        }

        /// <summary>
        /// Evaluates if the DoubleDoubleComponent instance is less than 
        /// the given Double value.
        /// </summary>
        /// <param name="value">The value to compare to.</param>
        /// <returns>True if the DoubleDoubleComponent instance is less
        /// than <paramref name="value"/>; false otherwise.</returns>
        public Boolean LessThan(Double value)
        {
            return LessThan(new DoubleDoubleComponent(value));
        }

        /// <summary>
        /// Evaluates if the DoubleDoubleComponent instance is less than 
        /// or equal to the given Double value.
        /// </summary>
        /// <param name="value">The value to compare to.</param>
        /// <returns>
        /// True if the DoubleDoubleComponent instance is less
        /// than or equal to <paramref name="value"/>; false otherwise.
        /// </returns>
        public Boolean LessThanOrEqualTo(Double value)
        {
            return LessThanOrEqualTo(new DoubleDoubleComponent(value));
        }

        #endregion

        #region IExponential<DoubleDoubleComponent> Members

        /// <summary>
        /// Raises the DoubleDoubleComponent value to the given exponent.
        /// <param name="exp">
        /// The value of the exponent.
        /// </param>
        /// <returns>
        /// The value of the DoubleDoubleComponent (the base) 
        /// raised to the given power.
        /// </returns>
        public DoubleDoubleComponent Power(Double exp)
        {
            if (exp == 0.0)
                return One;

            DoubleDoubleComponent r = new DoubleDoubleComponent(this);
            DoubleDoubleComponent s = One;
            int n = (int)System.Math.Abs(exp);

            if (n > 1)
            {
                // Use binary exponentiation 
                while (n > 0)
                {
                    if (n % 2 == 1)
                    {
                        s = s.Multiply(r);
                    }
                    n /= 2;
                    if (n > 0)
                        r = Square(r);
                }
            }
            else
            {
                s = r;
            }

            // Compute the reciprocal if n is negative. 
            if (exp < 0)
                return s.Reciprocal();
            return s;
        }

        /// <summary>
        /// Computes value <sup>2</sup>
        /// </summary>
        /// <param name="value">value <sup>2</sup></param>
        /// <returns></returns>
        private static DoubleDoubleComponent Square(DoubleDoubleComponent value)
        {
            return value.Multiply(value);
        }

        /// <summary>
        /// Computes the value of the square root of the DoubleDoubleComponent.
        /// </summary>
        /// <returns>
        /// The value of the square root of the DoubleDoubleComponent.
        /// </returns>
        public DoubleDoubleComponent Sqrt()
        {
            // Strategy:  Use Karp's trick:  if x is an approximation to sqrt(a), then
            //            sqrt(a) = a*x + [a - (a*x)^2] * x / 2   (approx)

            // The approximation is accurate to twice the accuracy of x.
            //  Also, the multiplication (a*x) and [-]*x can be done with
            // only half the precision.

            if (IsZero())
                return new DoubleDoubleComponent(0.0);

            if (IsNegative())
            {
                return NaN;
            }

            double x = 1.0 / System.Math.Sqrt(_high);
            double ax = _high * x;

            DoubleDoubleComponent axdd = new DoubleDoubleComponent(ax);
            DoubleDoubleComponent diffSq = Subtract(Square(axdd));
            double d2 = diffSq._high * (x * 0.5);

            return axdd.Add(new DoubleDoubleComponent(d2));
        }

        /// <summary>
        /// Computes the log of the DoubleDoubleComponent in the
        /// <paramref name="newBase">given base</paramref>.
        /// </summary>
        /// <param name="newBase">The base to compute the log in.</param>
        /// <returns>
        /// The log of the DoubleDoubleComponent in the new base given.
        /// </returns>
        public DoubleDoubleComponent Log(Double newBase)
        {
            return new DoubleDoubleComponent(System.Math.Log(_high, newBase));
        }

        /// <summary>
        /// Computes the log of the DoubleDoubleComponent in base e.
        /// </summary>
        /// <returns>The natural log of the DoubleDoubleComponent.</returns>
        public DoubleDoubleComponent Log()
        {
            return new DoubleDoubleComponent(System.Math.Log(_high));
        }

        /// <summary>
        /// Computes e to the power of the DoubleDoubleComponent.
        /// </summary>
        /// <returns>
        /// The natural log base, e, raised to the power 
        /// of the value of the DoubleDoubleComponent.
        /// </returns>
        public DoubleDoubleComponent Exp()
        {
            return new DoubleDoubleComponent(System.Math.Exp(_high));
        }

        #endregion

        #region IExponential<Double> Members

        /// <summary>
        /// Raises the DoubleDoubleComponent value to the given 
        /// exponent, returned as a Double.
        /// <paramref name="power"/>.
        /// </summary>
        /// <param name="power">
        /// The value of the exponent.
        /// </param>
        /// <returns>
        /// The value of the DoubleDoubleComponent (the base) 
        /// raised to the given power.
        /// </returns>
        Double IExponential<Double>.Power(Double power)
        {
            return Power(power)._high;
        }

        /// <summary>
        /// Computes the value of the square root of the DoubleDoubleComponent,
        /// returned as a Double.
        /// </summary>
        /// <returns>
        /// The value of the square root of the DoubleDoubleComponent.
        /// </returns>
        Double IExponential<Double>.Sqrt()
        {
            return Sqrt()._high;
        }

        Double IExponential<Double>.Log(Double newBase)
        {
            return Log(newBase)._high;
        }

        /// <summary>
        /// Computes the log of the DoubleDoubleComponent in base 10,
        /// returned as a Double.
        /// </summary>
        /// <returns>
        /// The log of the DoubleDoubleComponent in the new base given.
        /// </returns>
        Double IExponential<Double>.Log()
        {
            return Log()._high;
        }

        /// <summary>
        /// Computes the log of the DoubleDoubleComponent in base e,
        /// returned as a Double.
        /// </summary>
        /// <returns>The natural log of the DoubleDoubleComponent.</returns>
        Double IExponential<Double>.Exp()
        {
            return Exp()._high;
        }

        #endregion

        #region IComputable<DoubleDoubleComponent> Members

        /// <summary>
        /// Computes the absolute value of the DoubleDoubleComponent.
        /// </summary>
        /// <returns>
        /// The absolute value of the DoubleDoubleComponent's value.
        /// </returns>
        public DoubleDoubleComponent Abs()
        {
            if (IsNaN()) return NaN;
            if (IsNegative())
                return Negative();
            return new DoubleDoubleComponent(this);
        }

        /// <summary>
        /// Sets the value of the DoubleDoubleComponent.
        /// </summary>
        /// <param name="value">
        /// The value to set the DoubleDoubleComponent to, cast to a Double.
        /// </param>
        /// <returns>
        /// A DoubleDoubleComponent with the given <paramref name="value"/>.
        /// </returns>
        public DoubleDoubleComponent Set(Double value)
        {
            _high = value;
            _low = 0d;
            return this;
        }

        #endregion

        #region IComputable<Double> Members

        /// <summary>
        /// Computes the absolute value of the DoubleDoubleComponent,
        /// returned as a Double.
        /// </summary>
        /// <returns>
        /// The absolute value of the DoubleDoubleComponent's value.
        /// </returns>
        Double IComputable<Double>.Abs()
        {
            return Abs()._high;
        }

        /// <summary>
        /// Computes the absolute value of the DoubleDoubleComponent,
        /// returned as a Double.
        /// </summary>
        /// <returns>
        /// The absolute value of the DoubleDoubleComponent's value.
        /// </returns>
        Double IComputable<Double>.Set(Double value)
        {
            _high = value;
            return value;
        }

        #endregion

        #region IConvertible Members

        /// <summary>
        /// Gets the TypeCode value for the DoubleDoubleComponent.
        /// </summary>
        /// <returns><see cref="TypeCode.Double"/></returns>
        public TypeCode GetTypeCode()
        {
            return TypeCode.Double;
        }

        /// <summary>
        /// Converts the DoubleDoubleComponent to a <see cref="Boolean"/> value.
        /// </summary>
        /// <param name="provider">
        /// An <see cref="IFormatProvider"/> instance used to 
        /// help convert the DoubleDoubleComponent value.
        /// </param>
        /// <returns>The DoubleDoubleComponent as a <see cref="Boolean"/>.</returns>
        public Boolean ToBoolean(IFormatProvider provider)
        {
            return Convert.ToBoolean(_high, provider);
        }

        /// <summary>
        /// Converts the DoubleDoubleComponent to a <see cref="Byte"/> value.
        /// </summary>
        /// <param name="provider">
        /// An <see cref="IFormatProvider"/> instance used to 
        /// help convert the DoubleDoubleComponent value.
        /// </param>
        /// <returns>The DoubleDoubleComponent as a <see cref="Byte"/>.</returns>
        public Byte ToByte(IFormatProvider provider)
        {
            return Convert.ToByte(_high, provider);
        }

        /// <summary>
        /// Converts the DoubleDoubleComponent to a <see cref="Char"/> value.
        /// </summary>
        /// <param name="provider">
        /// An <see cref="IFormatProvider"/> instance used to 
        /// help convert the DoubleDoubleComponent value.
        /// </param>
        /// <returns>The DoubleDoubleComponent as a <see cref="Char"/>.</returns>
        public Char ToChar(IFormatProvider provider)
        {
            return Convert.ToChar(_high, provider);
        }

        /// <summary>
        /// Converts the DoubleDoubleComponent to a <see cref="DateTime"/> value.
        /// </summary>
        /// <param name="provider">
        /// An <see cref="IFormatProvider"/> instance used to 
        /// help convert the DoubleDoubleComponent value.
        /// </param>
        /// <returns>The DoubleDoubleComponent as a <see cref="DateTime"/>.</returns>
        public DateTime ToDateTime(IFormatProvider provider)
        {
            return Convert.ToDateTime(_high, provider);
        }

        /// <summary>
        /// Converts the DoubleDoubleComponent to a <see cref="Decimal"/> value.
        /// </summary>
        /// <param name="provider">
        /// An <see cref="IFormatProvider"/> instance used to 
        /// help convert the DoubleDoubleComponent value.
        /// </param>
        /// <returns>The DoubleDoubleComponent as a <see cref="Decimal"/>.</returns>
        public Decimal ToDecimal(IFormatProvider provider)
        {
            return Convert.ToDecimal(_high, provider);
        }

        /// <summary>
        /// Converts the DoubleDoubleComponent to a <see cref="Double"/> value.
        /// </summary>
        /// <param name="provider">
        /// An <see cref="IFormatProvider"/> instance used to 
        /// help convert the DoubleDoubleComponent value.
        /// </param>
        /// <returns>The DoubleDoubleComponent as a <see cref="Double"/>.</returns>
        public Double ToDouble(IFormatProvider provider)
        {
            return _high;
        }

        /// <summary>
        /// Converts the DoubleDoubleComponent to a <see cref="Int16"/> value.
        /// </summary>
        /// <param name="provider">
        /// An <see cref="IFormatProvider"/> instance used to 
        /// help convert the DoubleDoubleComponent value.
        /// </param>
        /// <returns>The DoubleDoubleComponent as a <see cref="Int16"/>.</returns>
        public Int16 ToInt16(IFormatProvider provider)
        {
            return Convert.ToInt16(_high, provider);
        }

        /// <summary>
        /// Converts the DoubleDoubleComponent to a <see cref="Int32"/> value.
        /// </summary>
        /// <param name="provider">
        /// An <see cref="IFormatProvider"/> instance used to 
        /// help convert the DoubleDoubleComponent value.
        /// </param>
        /// <returns>The DoubleDoubleComponent as a <see cref="Int32"/>.</returns>
        public Int32 ToInt32(IFormatProvider provider)
        {
            return Convert.ToInt32(_high, provider);
        }

        /// <summary>
        /// Converts the DoubleDoubleComponent to a <see cref="Int64"/> value.
        /// </summary>
        /// <param name="provider">
        /// An <see cref="IFormatProvider"/> instance used to 
        /// help convert the DoubleDoubleComponent value.
        /// </param>
        /// <returns>The DoubleDoubleComponent as a <see cref="Int64"/>.</returns>
        public Int64 ToInt64(IFormatProvider provider)
        {
            return Convert.ToInt64(_high, provider);
        }

        /// <summary>
        /// Converts the DoubleDoubleComponent to a <see cref="SByte"/> value.
        /// </summary>
        /// <param name="provider">
        /// An <see cref="IFormatProvider"/> instance used to 
        /// help convert the DoubleDoubleComponent value.
        /// </param>
        /// <returns>The DoubleDoubleComponent as a <see cref="SByte"/>.</returns>
        [CLSCompliant(false)]
        public SByte ToSByte(IFormatProvider provider)
        {
            return Convert.ToSByte(_high, provider);
        }

        /// <summary>
        /// Converts the DoubleDoubleComponent to a <see cref="Single"/> value.
        /// </summary>
        /// <param name="provider">
        /// An <see cref="IFormatProvider"/> instance used to 
        /// help convert the DoubleDoubleComponent value.
        /// </param>
        /// <returns>The DoubleDoubleComponent as a <see cref="Single"/>.</returns>
        public Single ToSingle(IFormatProvider provider)
        {
            return Convert.ToSingle(_high, provider);
        }

        /// <summary>
        /// Converts the DoubleDoubleComponent to a <see cref="String"/> value.
        /// </summary>
        /// <param name="provider">
        /// An <see cref="IFormatProvider"/> instance used to 
        /// help convert the DoubleDoubleComponent value.
        /// </param>
        /// <returns>The DoubleDoubleComponent as a <see cref="String"/>.</returns>
        public String ToString(IFormatProvider provider)
        {
            return Convert.ToString(_high, provider);
        }

        /// <summary>
        /// Converts the DoubleDoubleComponent to a value of the given type.
        /// </summary>
        /// <param name="conversionType">
        /// Type to convert to.
        /// </param>
        /// <param name="provider">
        /// An <see cref="IFormatProvider"/> instance used to 
        /// help convert the DoubleDoubleComponent value.
        /// </param>
        /// <returns>
        /// The DoubleDoubleComponent as a value of <paramref name="conversionType"/>.
        /// </returns>
        public Object ToType(Type conversionType, IFormatProvider provider)
        {
            return Convert.ChangeType(_high, conversionType, provider);
        }

        /// <summary>
        /// Converts the DoubleDoubleComponent to a <see cref="UInt16"/> value.
        /// </summary>
        /// <param name="provider">
        /// An <see cref="IFormatProvider"/> instance used to 
        /// help convert the DoubleDoubleComponent value.
        /// </param>
        /// <returns>The DoubleDoubleComponent as a <see cref="UInt16"/>.</returns>
        [CLSCompliant(false)]
        public UInt16 ToUInt16(IFormatProvider provider)
        {
            return Convert.ToUInt16(_high, provider);
        }

        /// <summary>
        /// Converts the DoubleDoubleComponent to a <see cref="UInt32"/> value.
        /// </summary>
        /// <param name="provider">
        /// An <see cref="IFormatProvider"/> instance used to 
        /// help convert the DoubleDoubleComponent value.
        /// </param>
        /// <returns>The DoubleDoubleComponent as a <see cref="UInt32"/>.</returns>
        [CLSCompliant(false)]
        public UInt32 ToUInt32(IFormatProvider provider)
        {
            return Convert.ToUInt32(_high, provider);
        }

        /// <summary>
        /// Converts the DoubleDoubleComponent to a <see cref="UInt64"/> value.
        /// </summary>
        /// <param name="provider">
        /// An <see cref="IFormatProvider"/> instance used to 
        /// help convert the DoubleDoubleComponent value.
        /// </param>
        /// <returns>The DoubleDoubleComponent as a <see cref="UInt64"/>.</returns>
        [CLSCompliant(false)]
        public UInt64 ToUInt64(IFormatProvider provider)
        {
            return Convert.ToUInt64(_high, provider);
        }

        #endregion

        #region IFormattable Members

        /// <summary>
        /// Generates a String representation of the DoubleDoubleComponent.
        /// </summary>
        /// <param name="format">The format String to use in formatting.</param>
        /// <param name="formatProvider">
        /// An <see cref="IFormatProvider"/> instance used to 
        /// help format the DoubleDoubleComponent value.
        /// </param>
        /// <returns>
        /// A formatted String which represents the DoubleDoubleComponent value.
        /// </returns>
        public String ToString(String format, IFormatProvider formatProvider)
        {
            return ToString(); //_value.ToString(format, formatProvider);
        }

        #endregion

        /// <summary>
        /// Returns the sum of the Object and <paramref name="b"/>.
        /// It must not modify the value of the Object.
        /// </summary>
        /// <param name="b">The second operand.</param>
        /// <returns>The sum.</returns>
        public DoubleDoubleComponent Add(Double b)
        {
            return Add( new DoubleDoubleComponent(b));
        }

        /// <summary>
        /// Returns the quotient of the Object and <paramref name="b"/>.
        /// It must not modify the value of the Object.
        /// </summary>
        /// <param name="b">The second operand.</param>
        /// <returns>The quotient.</returns>
        public DoubleDoubleComponent Divide(Double b)
        {
            return Divide(new DoubleDoubleComponent(b));
        }

        /// <summary>
        /// Returns the product of the Object and <paramref name="b"/>.
        /// It must not modify the value of the Object.
        /// </summary>
        /// <param name="b">The factor to multiply by.</param>
        /// <returns>The product.</returns>
        public DoubleDoubleComponent Multiply(Double b)
        {
            return Multiply(new DoubleDoubleComponent(b));
        }

        /// <summary>
        /// Returns the difference of the Object and <paramref name="b"/>.
        /// It must not modify the value of the Object.
        /// </summary>
        /// <param name="b">The second operand.</param>
        /// <returns>The difference.</returns>
        public DoubleDoubleComponent Subtract(Double b)
        {
            return Subtract(new DoubleDoubleComponent(b));
        }


#region "from DoubleDouble.java"

        ///<summary>
        /// Returns a DoubleDoubleComponent whose value is  <value>1 / this</value>.
        ///</summary>
        ///<returns>the reciprocal of this value</returns>
        public DoubleDoubleComponent Reciprocal()
        {
            double hc, tc, hy, ty, C, c, U, u;
            C = 1.0 / _high;
            c = SPLIT * C;
            hc = c - C;
            u = SPLIT * _high;
            hc = c - hc; tc = C - hc; hy = u - _high; U = C * _high; hy = u - hy; ty = _high - hy;
            u = (((hc * hy - U) + hc * ty) + tc * hy) + tc * ty;
            c = ((((1.0 - U) - u)) - C * _low) / _high;

            double zhi = C + c;
            double zlo = (C - zhi) + c;
            return new DoubleDoubleComponent(zhi, zlo);
        }

        /// <summary>
        /// Returns the string representation of this value in standard notation.
        /// </summary>
        /// <returns>The string representation in standard notation</returns>
        public String ToStandardNotation()
        {
            String specialStr = GetSpecialNumberString();
            if (specialStr != null)
                return specialStr;

            int[] magnitude = new int[1];
            String sigDigits = ExtractSignificantDigits(true, magnitude);
            int decimalPointPos = magnitude[0] + 1;

            String num = sigDigits;
            // add a leading 0 if the decimal point is the first char
            if (sigDigits[0] == '.')
            {
                num = "0" + sigDigits;
            }
            else if (decimalPointPos < 0)
            {
                num = "0." + StringOfChar('0', -decimalPointPos) + sigDigits;
            }
            else if (sigDigits.IndexOf('.') == -1)
            {
                // no point inserted - sig digits must be smaller than magnitude of number
                // add zeroes to end to make number the correct size
                int numZeroes = decimalPointPos - sigDigits.Length;
                String zeroes = StringOfChar('0', numZeroes);
                num = sigDigits + zeroes + ".0";
            }

            if (IsNegative())
                return "-" + num;
            return num;
        }

        private const int MaxPrintDigits = 32;
        private const String SciNotExponentChar = "E";
        private const String SciNotZero = "0.0E0";

        ///<summary>
        /// Returns the string representation of this value in scientific notation.
        ///</summary>
        ///<returns>The string representation in scientific notation </returns>
        ///<exception cref="ArgumentException"></exception>
        public String ToSciNotation()
        {
            // special case zero, to allow as
            if (IsZero())
                return SciNotZero;

            String specialStr = GetSpecialNumberString();
            if (specialStr != null)
                return specialStr;

            int[] magnitude = new int[1];
            String digits = ExtractSignificantDigits(false, magnitude);
            String expStr = SciNotExponentChar + magnitude[0];

            // should never have leading zeroes
            // MD - is this correct?  Or should we simply strip them if they are present?
            if (digits[0] == '0')
            {
                throw new ArgumentException("Found leading zero: " + digits);
            }

            // add decimal point
            String trailingDigits = "";
            if (digits.Length > 1)
                trailingDigits = digits.Substring(1);
            String digitsWithDecimal = digits[0] + "." + trailingDigits;

            if (IsNegative())
                return "-" + digitsWithDecimal + expStr;
            return digitsWithDecimal + expStr;
        }

        /// <summary>
        /// Extracts the significant digits in the decimal representation of the argument.
        /// A decimal point may be optionally inserted in the string of digits
        /// (as long as its position lies within the extracted digits
        /// - if not, the caller must prepend or append the appropriate zeroes and decimal point).
        /// </summary>
        /// <param name="insertDecimalPoint"></param>
        /// <param name="magnitude"></param>
        /// <returns>the string containing the significant digits and possibly a decimal point</returns>
        private String ExtractSignificantDigits(Boolean insertDecimalPoint, int[] magnitude)
        {
            DoubleDoubleComponent y = Abs();
            // compute *correct* magnitude of y
            int mag = Magnitude(y._high);
            DoubleDoubleComponent scale = Ten.Power(mag);
            y = y.Divide(scale);

            // fix magnitude if off by one
            if (y.GreaterThan(Ten))
            {
                y = y.Divide(Ten);
                mag += 1;
            }
            else if (y.LessThan(One))
            {
                y = y.Multiply(Ten);
                mag -= 1;
            }

            int decimalPointPos = mag + 1;
            StringBuilder buf = new StringBuilder();
            const int numDigits = MaxPrintDigits - 1;
            for (int i = 0; i <= numDigits; i++)
            {
                if (insertDecimalPoint && i == decimalPointPos)
                {
                    buf.Append('.');
                }
                int digit = (int)y._high;

                //
                // If a negative remainder is encountered, simply terminate the extraction.  
                // This is robust, but maybe slightly inaccurate.
                // My current hypothesis is that negative remainders only occur for very small lo components, 
                // so the inaccuracy is tolerable
                //
                if (digit < 0)
                {
                    break;
                    // throw new IllegalStateException("Internal errror: found digit = " + digit);
                }
                Boolean rebiasBy10 = false;
                char digitChar;
                if (digit > 9)
                {
                    // set flag to re-bias after next 10-shift
                    rebiasBy10 = true;
                    // output digit will end up being '9'
                    digitChar = '9';
                }
                else
                {
                    digitChar = (char)('0' + digit);
                }
                buf.Append(digitChar);
                y = (y.Subtract(new DoubleDoubleComponent(digit)).Multiply(Ten));
                if (rebiasBy10)
                    y = y.Add(Ten);

                Boolean continueExtractingDigits = true;
                //
                // Heuristic check: if the remaining portion of 
                // is non-positive, assume that output is complete
                //
                //  if (y.hi <= 0.0)
                //      if (y.hi < 0.0)
                //          continueExtractingDigits = false;
                //
                // Check if remaining digits will be 0, and if so don't output them.
                // Do this by comparing the magnitude of the remainder with the expected precision.
                //
                int remMag = Magnitude(y._high);
                if (remMag < 0 && System.Math.Abs(remMag) >= (numDigits - i))
                    continueExtractingDigits = false;
                if (!continueExtractingDigits)
                    break;
            }
            magnitude[0] = mag;
            return buf.ToString();
        }

        /// <summary>
        /// Creates a string of a given length containing the given character
        /// </summary>
        /// <param name="ch">ch the character to be repeated</param>
        /// <param name="len">len the len of the desired string</param>
        /// <returns>the string</returns>
        private static String StringOfChar(char ch, int len)
        {
            StringBuilder buf = new StringBuilder();
            for (int i = 0; i < len; i++)
            {
                buf.Append(ch);
            }
            return buf.ToString();
        }

        /// <summary>
        /// Returns the string for this value if it has a known representation (E.g. NaN or 0.0).
        /// </summary>
        /// <returns>the string for this special number</returns>
        /// <returns>null if the number is not a special number</returns>
        private String GetSpecialNumberString()
        {
            if (IsZero()) return "0.0";
            return IsNaN() ? "NaN " : null;
        }

        /// <summary>
        /// Determines the decimal magnitude of a number.
        /// The magnitude is the exponent of the greatest power of 10 which is less than or equal to the number.
        /// </summary>
        /// <param name="x">the number to find the magnitude of</param>
        /// <returns>the decimal magnitude of x</returns>
        private static int Magnitude(double x)
        {
            double xAbs = System.Math.Abs(x);
            double xLog10 = System.Math.Log(xAbs) / System.Math.Log(10);
            int xMag = (int)System.Math.Floor(xLog10);
            //
            // Since log computation is inexact, there may be an off-by-one error
            // in the computed magnitude. 
            // Following tests that magnitude is correct, and adjusts it if not
            //
            double xApprox = System.Math.Pow(10, xMag);
            if (xApprox * 10 <= xAbs)
                xMag += 1;

            return xMag;
        }

        ///<summary>
        /// Tests whether this value is equal to 0.
        ///</summary>
        ///<returns>true if this value is equal to 0</returns>
        public Boolean IsZero()
        {
            return _high == 0.0 && _low == 0.0;
        }

        ///<summary>
        /// Tests whether this value is less than 0.
        ///</summary>
        ///<returns>true if this value is less than 0</returns>
        public Boolean IsNegative()
        {
            return _high < 0.0 || (_high == 0.0 && _low < 0.0);
        }

        ///<summary>
        /// Tests whether this value is greater than 0.
        ///</summary>
        ///<returns>true if this value is greater than 0</returns>
        public Boolean IsPositive()
        {
            return _high > 0.0 || (_high == 0.0 && _low > 0.0);
        }

        ///<summary>
        /// Tests whether this value is NaN.
        ///</summary>
        ///<returns>true if this value is NaN</returns>
        public Boolean IsNaN() { return Double.IsNaN(_high); }

#endregion
    }
}